package com.topsec.manager.util;

import static org.slf4j.LoggerFactory.getLogger;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.slf4j.Logger;

import com.topsec.manager.entity.ResourceBean;


/**
 * @author zhaoys
 * @date 2017年6月19日 下午2:52:46
 */
public class FtpUtil {
    /**
     * 日志记录器
     */
    private static final Logger logger = getLogger(FtpUtil.class);
    private static String encoding = System.getProperty("file.encoding");
    /**
     * 本地存储目录
     */
    private static String localDir;
    /**
     * 文件路径通配符 默认列出所有
     */
    private static String regEx = "*";
    /**
     * 指定要下载的文件名
     */
    private static String downloadFileName;
    /**
     * 客户端
     */
    private static FTPClient client;

    /**
     * 下载所有文件
     *
     * @param localDir
     * @param remoteDir
     */
    public static List<File> download(FTPClient client, String localDir) {
        FtpUtil.client = client;
        FtpUtil.localDir = localDir;
        return download();
    }

    /**
     * 下载指定文件
     *
     * @param client           客户端
     * @param downloadFileName 指定要下载的文件名称
     * @param localDir         本地路径
     * @return
     */
    public static File download(FTPClient client, String downloadFileName,
                                String localDir) {
        FtpUtil.client = client;
        FtpUtil.downloadFileName = downloadFileName;
        FtpUtil.localDir = localDir;
        List<File> download = download();
        if (download.size() > 0) {
            return download.get(0);
        }
        return null;
    }

    /**
     * 上传文件文件集合
     *
     * @param files     上传的文件
     * @param remoteDir
     */
    public static void upload(List<File> files, String remoteDir) {
        upload(files);
    }

    /**
     * 上传单个文件
     *
     * @param file
     */
    public static void upload(File file) {
        List<File> files = new ArrayList<File>();
        files.add(file);
        upload(files);
    }

    /**
     * 删除文件
     *
     * @param file
     */
    public static void del(String filepath) {
        try {
            client.deleteFile(filepath);
        } catch (IOException e) {
            throw new RuntimeException("服务器上删除文件对象失败" + e.getMessage());
        }
    }

    /**
     * 关闭连接
     *
     * @param client 客户端
     */
    public static void close(FTPClient client) {
        try {
            if (client != null) {
                client.logout();
            }
        } catch (Exception e) {
            throw new RuntimeException("关闭客户端连接失败" + e.getMessage());
        }
    }

    /**
     * 获取ftp连接
     *
     * @param ResourceBean 资源
     * @return FTPClient ftp客户端<br/>
     */
    public static FTPClient getConnection(ResourceBean r) {
        FTPClient client = new FTPClient();
        // 设置超时时间
        client.setConnectTimeout(30000);
        try {
            // 1、连接服务器
            if (!client.isConnected()) {
                // 如果采用默认端口，可以使用client.connect(host)的方式直接连接FTP服务器
                client.connect(r.getHost(), r.getPort());
                // 登录
                client.login(r.getUsername(), r.getPassword());
                // 获取ftp登录应答码
                int reply = client.getReplyCode();
                // 验证是否登陆成功
                if (!FTPReply.isPositiveCompletion(reply)) {
                    logger.info("未连接到FTP，用户名或密码错误。");
                    client.disconnect();
                    throw new RuntimeException("未连接到FTP，用户名或密码错误。");
                } else {
                    logger.info("FTP连接成功。Monitor_Ip:" + r.getHost() + "PORT:"
                            + r.getPort());
                }
                // 2、设置连接属性
                client.setControlEncoding(encoding);
                // 设置以二进制方式传输
                client.setFileType(FTPClient.BINARY_FILE_TYPE);
                client.enterLocalPassiveMode();
            }
        } catch (SocketException e) {
            try {
                client.disconnect();
            } catch (IOException e1) {
            }
            logger.error("连接FTP服务器失败" + e.getMessage());
            throw new RuntimeException("连接FTP服务器失败" + e.getMessage());
        } catch (IOException e) {
        }
        return client;
    }

    public OutputStream getOutputStream(String fileName) {
        OutputStream os = null;
        try {
            /*
             * client.changeWorkingDirectory(remoteDir); logger.info("切换至工作目录【"
             * + remoteDir + "】");
             */
            os = client.storeFileStream(fileName);
            if (os == null)
                throw new RuntimeException("服务器上创建文件对象失败");
            return os;
        } catch (IOException e) {
            logger.error("服务器上创建文件对象失败" + e.getMessage());
            throw new RuntimeException("服务器上创建文件对象失败" + e.getMessage());
        }
    }

    /**
     * 下载
     *
     * @param ResourceBean
     *            资源
     * @return FTPClient ftp客户端<br/>
     */
    /**
     * 下载文件
     */
    private static List<File> download() {
        List<File> files = null;
        InputStream is = null;
        File downloadFile = null;
        try {
            // 1、读取远程文件
            FTPFile[] ftpFiles = client.listFiles(regEx);
            if (ftpFiles.length == 0) {
                logger.warn("文件数为0，没有可下载的文件！");
                return null;
            }
            logger.info("准备下载" + ftpFiles.length + "个文件");
            // 2、保存文件到本地
            for (FTPFile file : ftpFiles) {
                if (downloadFileName != null) {
                    // 如果有指定下载的文件
                    if (!file.getName().equals(downloadFileName)) {
                        continue;
                    }
                }
                if (files == null)
                    files = new ArrayList<File>();
                is = client.retrieveFileStream(file.getName());
                if (is == null)
                    throw new RuntimeException("下载失败，检查文件是否存在");
                downloadFile = new File(localDir + file.getName());
                FileOutputStream fos = FileUtils.openOutputStream(downloadFile);
                IOUtils.copy(is, fos);
                client.completePendingCommand();
                IOUtils.closeQuietly(is);
                IOUtils.closeQuietly(fos);
                files.add(downloadFile);
            }
            logger.info("文件下载成功,下载文件路径：" + localDir);
            return files;
        } catch (IOException e) {
            logger.error("下载文件失败" + e.getMessage());
            throw new RuntimeException("下载文件失败" + e.getMessage());
        }
    }

    /**
     * 上传文件
     *
     * @param files
     */
    private static void upload(List<File> files) {
        OutputStream os = null;
        try {
            // 2、取本地文件
            if (files == null || files.size() == 0) {
                logger.warn("文件数为0，没有找到可上传的文件");
                return;
            }
            logger.info("准备上传" + files.size() + "个文件");
            // 3、上传到FTP服务器
            for (File file : files) {
                // 1、设置远程FTP目录
                /*
                 * client.changeWorkingDirectory(remoteDir);
                 * logger.info("切换至工作目录【" + remoteDir + "】");
                 */
                os = client.storeFileStream(file.getName());
                if (os == null)
                    throw new RuntimeException("上传失败，请检查是否有上传权限");
                IOUtils.copy(new FileInputStream(file), os);
                IOUtils.closeQuietly(os);
            }
        } catch (IOException e) {
            logger.error("上传文件失败" + e.getMessage());
            throw new RuntimeException("上传文件失败" + e.getMessage());
        }
    }
}
